package com.dsbj.icardservice.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dsbj.common.msg.ResponseMessage;
import com.dsbj.icardservice.entity.Reservation;
import com.dsbj.icardservice.entity.ReservationPrimary;
import com.dsbj.icardservice.entity.SerialNumber;
import com.dsbj.icardservice.mapper.ReservationMapper;
import com.dsbj.icardservice.mapper.ReservationPrimaryMapper;
import com.dsbj.icardservice.model.WorkflowFieldInfo;
import com.dsbj.icardservice.utils.DateUtils;
import com.dsbj.icardservice.utils.PropertyUtil;
import com.dsbj.icardservice.utils.strprocess.Time_convert;
import com.dsbj.icardservice.webserviceclient.dsbjpmc.AllowUser;
import com.dsbj.icardservice.webserviceclient.ecology.docimage.*;
import com.dsbj.icardservice.webserviceclient.ecology.workflow.WorkflowService;
import com.dsbj.icardservice.webserviceclient.ecology.workflow.WorkflowServicePortType;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;
import sun.misc.BASE64Decoder;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ReservationService {

	@Autowired
	private ReservationMapper reservationMapper;

	@Autowired
	private ReservationPrimaryMapper mapper;

	@Autowired
	private SerialNumberService serialNumberService;

	@Autowired
	private EcologyWebService ecologyWebService;

	@Autowired
	DataSourceTransactionManager dataSourceTransactionManager;

	@Autowired
	TransactionDefinition transactionDefinition;

	@Autowired
	private ReservationPrimaryMapper reservationPrimaryMapper;



	public List<Reservation> getAllRecords() {
		return reservationMapper.selectList(null);
	}

	public List<Reservation> getReservationById(String id) {

		List<Reservation> list = new ArrayList<>();
		list.add(reservationMapper.selectById(id));

		QueryWrapper<Reservation> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("id", id);
		list.add(reservationMapper.selectOne(queryWrapper));

		list.add(reservationMapper.selectOne(
				new QueryWrapper<Reservation>()
						.lambda()
						.eq(Reservation::getId, id)));

		list.add(reservationMapper.getById(id));
		list.add(reservationMapper.getByIdXml(id));
		list.add(reservationMapper.getByIdWrapper(new QueryWrapper<Reservation>().eq("id", id)));
		return list;
	}


	/**
	 * 获取新的(未被预约单引用的)预约单号。tips: 该单号在预约单生成之前创建, 若此次预约单没有生成，则该单号可用于下一次的申请中。
	 *
	 * <p>该方法复杂，不简洁。</p>
	 *
	 * @param
	 * @return
	 * @author cjw 2019-09-25
	 */
	public String getNewReservationno() {

		String dateStr = Time_convert.getCurrentTime_onlyDigit();
		String sn_searchstr = "reservation" + dateStr;
		SerialNumber serialNumber = serialNumberService.findBySerialNumber(sn_searchstr);

		/**
		 * 若serialNumber不为null,分析serialNumber中的信息,并获取“未被使用”的reservationno。
		 */
		String rno = null;
		if (null != serialNumber) {
			String resultA = serialNumber.getResultA();
			rno = dateStr + resultA;

			//分析该rno是否已被预约单引用
			boolean isExist=checkReservationno_isExist(rno);

			//若isExist为true，reservationno已存在,循环更新serialNumber, 直到生成的reservationno未被使用为止
			while (isExist){
				//调用存储过程,更新或创建对应的记录
				Map<String, Object> map_procedure = new HashMap<String, Object>();
				map_procedure.put("str2", "reservation" + dateStr);
				map_procedure.put("long2", 2);
				serialNumberService.p1(map_procedure);

				resultA=map_procedure.get("no1").toString();
				rno=dateStr+resultA;
				isExist=checkReservationno_isExist(rno);
			}
			return rno;
		}else{
			/**
			 * 若serialNumber为null,直接创建serialNumber,并获得reservationno。
			 */

			//调用存储过程,更新或创建对应的记录
			Map<String, Object> map_procedure = new HashMap<String, Object>();
			map_procedure.put("str2", "reservation" + dateStr);
			map_procedure.put("long2", 2);
			serialNumberService.p1(map_procedure);

			String resultA=map_procedure.get("no1").toString();
			rno=dateStr+resultA;
			return rno;
		}
	}

	/**
	 * 分析该reservationno是否存在。
	 * @param
	 * @return
	 * @author cjw 2019-09-25
	 */
	public boolean checkReservationno_isExist(String reservationno) {
		QueryWrapper<com.dsbj.icardservice.entity.ReservationPrimary> queryWrapper=new QueryWrapper<>();
		queryWrapper.eq("RESERVATIONNO",reservationno);
		List<ReservationPrimary> reservations=mapper.selectList(queryWrapper);

		if(reservations.size()==0){
			return false;
		}else{
			return true;
		}
	}


	public ResponseMessage save(AllowUser user, ReservationPrimary reservationPrimary) {

		TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
		//根据登陆人工号OA查找部门
		ReservationPrimary rpy = getByCreateUserEmployeeno(user.getEmployeeNo().trim());
		if(null == rpy){
			dataSourceTransactionManager.commit(transactionStatus);//提交
			return ResponseMessage.error("登录人工号无OA权限，请联系系统管理员！");
		}

		//分析该访客申请单是否已存在，若已存在给出提示信息。
		ReservationPrimary reservationPrimary_exist=reservationPrimaryMapper.selectOne(
				new QueryWrapper<ReservationPrimary>().eq("RESERVATIONNO",reservationPrimary.getReservationno())
		);
		if(reservationPrimary_exist!=null){
			dataSourceTransactionManager.commit(transactionStatus);//提交
			return ResponseMessage.error("存入访客单失败,该表中已存在该单号!");
		}

		Date nowDate = new Date();
		///先保存主表
		reservationPrimary.setCreateUserEmployeeno(user.getEmployeeNo());
		reservationPrimary.setCreateUserDeptno(rpy.getDepartmentcode());
		reservationPrimary.setStatus(1);
		reservationPrimary.setCreateUser(user.getLoginName() + "-" + user.getName());
		reservationPrimary.setCreateTime(nowDate);
		mapper.insert(reservationPrimary);

		//保存子表
		if(!CollectionUtils.isEmpty(reservationPrimary.getReservationList())){

			reservationPrimary.getReservationList().forEach(reservation->{
				reservation.setCreateUser(reservationPrimary.getCreateUser());
				reservation.setStatus(1);
				reservation.setEmployeenoPhone(reservationPrimary.getEmployeenoPhone());
				reservation.setEmployeenoReception(reservationPrimary.getEmployeenoReception());
				reservation.setEmployeenameReception(reservationPrimary.getEmployeenameReception());
				reservation.setDeptno(reservationPrimary.getDeptno());
				reservation.setDeptname(reservationPrimary.getDeptname());
				reservation.setForecastVisitingTime(reservationPrimary.getForecastVisitingTime());
				reservation.setForecastDepartureTime(DateUtils.addSeconds(reservationPrimary.getForecastDepartureTime(),86399));
				reservation.setDistrictName(reservationPrimary.getDistrictName());
				reservation.setVisitorCompany(reservationPrimary.getVisitorCompany());
				reservation.setVisitingMatters(reservationPrimary.getVisitingMatters());
				reservation.setReservationno(reservationPrimary.getReservationno());
				reservation.setDistrictno(reservationPrimary.getDistrictno());
				reservation.setCompanyno(user.getCompanyno());

				String imagePath = PropertyUtil.getImageFileRoot()+reservation.getIdcardno()+".jpg";
				if(saveBase64ToImageFile(reservation.getPhotoBase64(),imagePath)){
					reservation.setIdcardnoUrl(PropertyUtil.getImageUrlRoot()+reservation.getIdcardno()+".jpg");
				}

				reservation.setCreateTime(nowDate);
				reservationMapper.insert(reservation);
			});
		}

		dataSourceTransactionManager.commit(transactionStatus);//提交


		//触发OA流程
		try{
			triggerWorkflow(user,rpy,reservationPrimary);
		}catch (Exception e){
			e.printStackTrace();
			dataSourceTransactionManager.rollback(transactionStatus);
			throw e;
		}
		return ResponseMessage.ok();
	}

	public String createAttachment(ReservationPrimary reservationPrimary) {

		DocServicePortType service = new DocService().getDocServiceHttpPort();
		String sessionCode = service.login(PropertyUtil.getOaDocUploaderName(), PropertyUtil.getOaDocUploaderPassword(), 0, "127.0.0.1");


		List<String> docIds = new ArrayList<>();
		ByteArrayOutputStream baos = null;
		for (Reservation reservation : reservationPrimary.getReservationList()) {
			if(StringUtils.isBlank(reservation.getIdcardnoUrl())){
				continue;
			}
			DocInfo doc = new DocInfo();

			doc.setDoccontent("");
			doc.setMaincategory(PropertyUtil.getOaDocUploadMaincategory());
			doc.setSubcategory(PropertyUtil.getOaDocUploadSubcategory());
			doc.setSeccategory(PropertyUtil.getOaDocUploadSeccategory());

			ArrayOfDocAttachment attachMents = new ArrayOfDocAttachment();

			DocAttachment da = new DocAttachment();
			String url = reservation.getIdcardnoUrl();
			String fileName = url.substring(url.indexOf("VisitorPhoto")+13);
			da.setImagefilename(fileName.substring(0,fileName.indexOf(".")));
			da.setFilename(fileName);
			doc.setDocSubject("访客预约"+da.getImagefilename());
			try {
				URL u = new URL(url);
				BufferedImage image = ImageIO.read(u);
				baos = new ByteArrayOutputStream();
				ImageIO.write(image, fileName.substring(fileName.indexOf(".")+1), baos);
				baos.flush();
				da.setFilecontent(reservation.getPhotoBase64());
				da.setIszip(1);
				attachMents.getDocAttachment().add(da);
				doc.setAttachments(attachMents);
				int id = service.createDoc(doc, sessionCode);
				if(id>0){
					docIds.add(String.valueOf(id));
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (baos != null) {
					try {
						baos.close();
					} catch (IOException e) {
					}
				}
			}
		}
		return docIds.stream().collect(Collectors.joining(","));
	}

	public boolean triggerWorkflow(AllowUser user, ReservationPrimary rpy, ReservationPrimary reservationPrimary) {
		//根据是否有照片先创建OA附件
		String attachmentIds = createAttachment(reservationPrimary);
		String workflowId = PropertyUtil.getWorkflowId();
		String creatorId = String.valueOf(rpy.getEmployeeId());
		String requestName = PropertyUtil.getWorkflowName()+user.getName()+"-"+ DateUtils.format(new Date(),"yyyy-MM-dd");


		List<WorkflowFieldInfo> mainDataList = new ArrayList<>();
		mainDataList.add(new WorkflowFieldInfo().fieldName("RESERVATIONNO").fieldValue(reservationPrimary.getReservationno()).canView(true).canEdit(true));
		mainDataList.add(new WorkflowFieldInfo().fieldName("DISTICTNO").fieldValue(reservationPrimary.getDistrictno()).canView(true).canEdit(true));
		mainDataList.add(new WorkflowFieldInfo().fieldName("DISTICTNAME").fieldValue(reservationPrimary.getDistrictName()).canView(true).canEdit(true));
		mainDataList.add(new WorkflowFieldInfo().fieldName("EMPLOYEENAME").fieldValue(reservationPrimary.getEmployeenameReception()).canView(true).canEdit(true));
		mainDataList.add(new WorkflowFieldInfo().fieldName("DEPTNAME").fieldValue(reservationPrimary.getDeptname()).canView(true).canEdit(true));
		mainDataList.add(new WorkflowFieldInfo().fieldName("EMPLOYEENO_PHONE").fieldValue(reservationPrimary.getEmployeenoPhone()).canView(true).canEdit(true));
		mainDataList.add(new WorkflowFieldInfo().fieldName("VISITOR_COMPANY").fieldValue(reservationPrimary.getVisitorCompany()).canView(true).canEdit(true));
		mainDataList.add(new WorkflowFieldInfo().fieldName("FORCAST_VISITING_TIME").fieldValue(DateUtils.format(reservationPrimary.getForecastVisitingTime(),"yyyy-MM-dd hh:mm:ss")).canView(true).canEdit(true));
		mainDataList.add(new WorkflowFieldInfo().fieldName("FORCAST_DEPARTURE_TIME").fieldValue(DateUtils.format(reservationPrimary.getForecastDepartureTime(),"yyyy-MM-dd hh:mm:ss")).canView(true).canEdit(true));
		mainDataList.add(new WorkflowFieldInfo().fieldName("DEPTNO").fieldValue(String.valueOf(rpy.getDepartmentId())).canView(true).canEdit(true));
		mainDataList.add(new WorkflowFieldInfo().fieldName("CREATE_USER").fieldValue(String.valueOf(rpy.getEmployeeId())).canView(true).canEdit(true));
		mainDataList.add(new WorkflowFieldInfo().fieldName("VISTING_MATTERS").fieldValue(reservationPrimary.getVisitingMatters()).canView(true).canEdit(true));
		mainDataList.add(new WorkflowFieldInfo().fieldName("djbh").fieldValue(reservationPrimary.getReservationno()).canView(true).canEdit(true));
		mainDataList.add(new WorkflowFieldInfo().fieldName("qhbmss").fieldValue("").canView(true).canEdit(true));
		mainDataList.add(new WorkflowFieldInfo().fieldName("mainPics").fieldValue(attachmentIds).canView(true).canEdit(true));


		List<List<WorkflowFieldInfo>> detailDataList = new ArrayList<>();
		if(!CollectionUtils.isEmpty(reservationPrimary.getReservationList())){
			for(Reservation reservation:reservationPrimary.getReservationList()){
				List<WorkflowFieldInfo> list = new ArrayList<>();
				list.add(new WorkflowFieldInfo().fieldName("VISITOR").fieldValue(reservation.getVisitor()).canView(true).canEdit(true));
				list.add(new WorkflowFieldInfo().fieldName("IDCARDNO").fieldValue(reservation.getIdcardno()).canView(true).canEdit(true));
				list.add(new WorkflowFieldInfo().fieldName("PHONE").fieldValue(reservation.getPhone()).canView(true).canEdit(true));
				list.add(new WorkflowFieldInfo().fieldName("CARRY_ITEMS").fieldValue(reservation.getCarryItems()).canView(true).canEdit(true));
				detailDataList.add(list);
			}
		}

		WorkflowServicePortType workflowService = new WorkflowService().getWorkflowServiceHttpPort();
		Integer requestid = Integer.parseInt(workflowService.doCreateWorkflowRequest(ecologyWebService.buildWorkflowRequest(workflowId,creatorId,"0",requestName,mainDataList,detailDataList), rpy.getEmployeeId()));

		if(requestid>0) return true;
		return false;
	}

	private boolean saveBase64ToImageFile(String imgStr,String imagePath)
	{  //对字节数组字符串进行Base64解码并生成图片
		if (imgStr == null) //图像数据为空
			return false;
		BASE64Decoder decoder = new BASE64Decoder();
		try
		{
			//Base64解码
			byte[] b = decoder.decodeBuffer(imgStr);
			for(int i=0;i<b.length;++i)
			{
				if(b[i]<0)
				{//调整异常数据
					b[i]+=256;
				}
			}
			//生成jpeg图片
			OutputStream out = new FileOutputStream(imagePath);
			out.write(b);
			out.flush();
			out.close();
			return true;
		}
		catch (Exception e)
		{
			return false;
		}
	}

	private ReservationPrimary getByCreateUserEmployeeno(String workcode) {
		return mapper.findByCreateUserEmployeeno(workcode);
	}
}
